package cn.com.bluemoon.daps.sync.core.sync.ptosc;

import cn.com.bluemoon.daps.common.datamarking.IDataMarking;
import cn.com.bluemoon.daps.sync.core.sync.sql.SqlStrBuilder;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;

@Data
public class PtOnlineSchemaChange implements IDataMarking {
    private static final List<PropertyValue> props_default = new ArrayList<PropertyValue>() {
        {
            this.add(new PropertyValue("max-lag", 3));
            this.add(new PropertyValue("chunk-size", 1000));
            this.add(new PropertyValue("chunk-size-limit", 4));
            this.add(new PropertyValue("chunk-time", 1));
            this.add(new PropertyValue("no-check-replication-filters", (Object) null));
            this.add(new PropertyValue("no-version-check", (Object) null));
//            this.add(new PropertyValue("alter-foreign-keys-method", "auto")); // 2021/6/28 注释掉，在ssh执行中报报错""
//            this.add(new PropertyValue("nocheck-unique-key-change", null)); // FIXME: 2021/6/28 测试中加上改参数可以避免执行add unique index的情况下，不允许执行（执行报错），线上去掉，报错，人工处理
            this.add(new PropertyValue("recursion-method", "none"));
            this.add(new PropertyValue("charset", "utf8"));
            this.add(new PropertyValue("critical-load", "\"Threads_running=200,Threads_connected=1000\""));
            this.add(new PropertyValue("max-load", "\"Threads_running=200,Threads_connected=1000\""));
            this.add(new PropertyValue("print", (Object) null));
            this.add(new PropertyValue("statistics", (Object) null));
            this.add(new PropertyValue("progress", "percentage,1"));
        }
    };
    /**
     * 命令的绝对路径 eg: /usr/xx/pt-online-schema-change
     */
    private String commandPath = "/usr/local/percona-toolkit-3.3.0/bin/pt-online-schema-change";
    /**
     * 连接用户 ,密码，ip
     */
    private String user;
    private String password;
    private String host;
    private Integer port;
    /**
     * alter
     */
    private String alter;
    private String database;
    private String table;
    private List<PropertyValue> props;
    private String outputLogPath;
    private boolean execute;

    public PtOnlineSchemaChange() {

    }

    public static void main(String[] args) {
        PtOnlineSchemaChange ptOnlineSchemaChange = builder().commandPath("/usr/local/percona-toolkit-3.3.0/bin/pt-online-schema-change").initCustomProps().execute(true).build();
        System.out.println(ptOnlineSchemaChange);
    }

    public PtOnlineSchemaChange(String commandPath, String user, String password, String host, Integer port, String alter, String database, String table, List<PropertyValue> props, boolean execute,  String outputLogPath) {
        this.commandPath = commandPath;
        this.user = user;
        this.password = password;
        this.host = host;
        this.port = port;
        this.alter = alter;
        this.database = database;
        this.table = table;
        this.props = props;
        this.execute = execute;
        this.outputLogPath = outputLogPath;
    }

    public static PtOnlineSchemaChangeBuilder builder() {
        return new PtOnlineSchemaChangeBuilder();
    }

    @Override
    public String toString(boolean dataMark) {
        SqlStrBuilder sb = new SqlStrBuilder();
        // h=192.168.234.4,P=3307,u=dsmanager,p=ufxErKTi,D=data_asset_platform,t=dap_standard_data_type \
        sb.append(this.commandPath).appendWs()
                .append("h=").append(this.host)
                .append(",P=").append(this.port)
                .append(",u=").append(this.user)
                .append(",p=").append(mask(dataMark, this.password))
                .append(",D=").append(this.database)
                .append(",t=").append(this.table)
                .appendWs().append("--alter").appendWs()
                .appendDQ(this.alter).appendWs()
                .appendWs();
        if (this.props != null && !this.props.isEmpty()) {
            for (PropertyValue prop : this.props) {
                if (prop.getValue() == null) {
                    if (!prop.getKey().startsWith("--")) {
                        prop.setKey("--" + prop.getKey());
                    }

                    sb.append(prop.getKey()).appendWs();
                } else {
                    if (!prop.getKey().startsWith("--")) {
                        prop.setKey("--" + prop.getKey());
                    }

                    sb.append(prop.getKey()).append("=").append(prop.getValue()).appendWs();
                }
            }
        }

        if (this.execute) {
            sb.appendWS("--execute");
        }
        if (outputLogPath != null){
            sb.append(" > ").append(outputLogPath);
        }

        String ptSql = sb.toString();
        return ptSql;
    }

    @Override
    public String toString() {
        return toString(false);
    }

    public String getCommandPath() {
        return this.commandPath;
    }

    public void setCommandPath(String commandPath) {
        this.commandPath = commandPath;
    }

    public String getUser() {
        return this.user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPassword() {
        return this.password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getHost() {
        return this.host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public Integer getPort() {
        return this.port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    public String getAlter() {
        return this.alter;
    }

    public void setAlter(String alter) {
        this.alter = alter;
    }

    public String getDatabase() {
        return this.database;
    }

    public void setDatabase(String database) {
        this.database = database;
    }

    public String getTable() {
        return this.table;
    }

    public void setTable(String table) {
        this.table = table;
    }

    public List<PropertyValue> getProps() {
        return this.props;
    }

    public void setProps(List<PropertyValue> props) {
        this.props = props;
    }

    public boolean isExecute() {
        return this.execute;
    }

    public void setExecute(boolean execute) {
        this.execute = execute;
    }

    public static class PtOnlineSchemaChangeBuilder {
        private String commandPath;
        private String user;
        private String password;
        private String host;
        private Integer port;
        private String alter;
        private String database;
        private String table;
        private List<PropertyValue> props;
        private boolean execute;
        private String outputLogPath;

        PtOnlineSchemaChangeBuilder() {
        }
        public PtOnlineSchemaChangeBuilder outputLogPath(String outputLogPath){
            this.outputLogPath = outputLogPath;
            return this;
        }
        public PtOnlineSchemaChangeBuilder commandPath(String commandPath) {
            this.commandPath = commandPath;
            return this;
        }

        public PtOnlineSchemaChangeBuilder user(String user) {
            this.user = user;
            return this;
        }

        public PtOnlineSchemaChangeBuilder password(String password) {
            this.password = password;
            return this;
        }


        public PtOnlineSchemaChangeBuilder host(String host) {
            this.host = host;
            return this;
        }

        public PtOnlineSchemaChangeBuilder port(Integer port) {
            this.port = port;
            return this;
        }

        public PtOnlineSchemaChangeBuilder alter(String alter) {
            this.alter = alter;
            return this;
        }

        public PtOnlineSchemaChangeBuilder database(String database) {
            this.database = database;
            return this;
        }

        public PtOnlineSchemaChangeBuilder table(String table) {
            this.table = table;
            return this;
        }

        public PtOnlineSchemaChangeBuilder props(List<PropertyValue> props) {
            this.props = props;
            return this;
        }

        public PtOnlineSchemaChangeBuilder execute(boolean execute) {
            this.execute = execute;
            return this;
        }

        public PtOnlineSchemaChange build() {
            return new PtOnlineSchemaChange(this.commandPath, this.user, this.password, this.host, this.port, this.alter, this.database, this.table, this.props, this.execute, this.outputLogPath);
        }

        public String toString() {
            return "PtOnlineSchemaChange.PtOnlineSchemaChangeBuilder(commandPath=" + this.commandPath + ", user=" + this.user + ", password=" + this.password + ", host=" + this.host + ", port=" + this.port + ", alter=" + this.alter + ", database=" + this.database + ", table=" + this.table + ", props=" + this.props + ", execute=" + this.execute + ")";
        }

        public PtOnlineSchemaChangeBuilder initCustomProps() {
            this.props = props_default;
            return this;
        }
    }
}
